package com.library.ezd.service.core;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.library.books.domain.Increment;
import com.library.books.domain.dto.BooksCopyIncrementDto;
import com.library.books.domain.vo.BooksCopyTempVo;
import com.library.books.domain.vo.print.PrintRequireInfoData;
import com.library.books.service.IBooksCopyService;
import com.library.books.service.IIncrementService;
import com.library.books.service.IPrintService;
import com.library.common.core.redis.RedisCache;
import com.library.common.enums.IncrementStatus;
import com.library.common.enums.PrintStatus;
import com.library.common.utils.books.BooksCopyUtils;
import com.library.ezd.enums.DataInfoOption;
import com.library.system.service.impl.SysConfigServiceImpl;
import com.payne.reader.Reader;
import com.payne.reader.bean.config.AntennaCount;
import com.payne.reader.bean.config.MemBank;
import com.payne.reader.bean.send.ReadConfig;
import com.payne.reader.process.ReaderImpl;
import com.library.ezd.handle.JSerialPortHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @Package: code
 * @ClassName: ezd30
 * @Author: Yin
 * @Date: 14:25
 * @Description: connection
 */
@Service
public class Ezd30Service {

    Logger log = LoggerFactory.getLogger(Ezd30Service.class);

    @Resource
    SysConfigServiceImpl sysConfigService;

    @Resource
    IIncrementService incrementService;

    @Resource
    IBooksCopyService booksCopyService;

    @Resource
    IPrintService printService;

    @Resource
    ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    RedisCache redisCache;

    /** 索引号循环计数器 */
    static AtomicLong atomicCnType = new AtomicLong();

    /** 读写器 */
    static Reader reader;

    /** 保持连接，不断开以bool控制持续读数据 */
    static boolean isStart;

    /** 中国图书分类当前使用-大分类 */
    static String typeUse;

    /** 中国图书分类当前使用-小分类 */
    static String cnTypeUse;

    int baud = 115200;

    String port ;

    int initVal = 1;

    /** 缓存需要构建书籍的key */
    String cacheBuildKey = "EZD30_RFID_BUILDBOOK";

    /** 缓存需要读取书籍的key */
    String cacheInfoKey = "EZD30_RFID_BOOKINFO";

    /** 缓存需要打印书籍副本的key */
    String cachePrintKey = "EZD30_RFID_BOOKPRINT";

    /** config_key */
    String configKey = "scan.ezdport";

    /** 操作：2025-01-22
     *  已分离出去，系统的内容存在云端，设备的代码存在本地
     */
    @PostConstruct
    synchronized void init() {
        try {
            String port = sysConfigService.selectConfigByKey(configKey);
//            String port = "COM1";
            initReader(port);
        }catch (Exception e) {
            log.error("读写器在项目启动时未能连接上");
        }
    }

    @PreDestroy
    public void destroy() {
        if(reader != null) {
            reader.disconnect();
        }
        log.info("系统退出 读写器stop：{}",reader);
    }

    /**
     * 初始化读写器
     *  - com
     *  - 波特率
     */
    private synchronized void initReader(String port) {
        log.info("[{}] 正在执行",Thread.currentThread().getName());
        log.info("读写器连接[Old:{},New:{}]",this.port,port);
        if(port == null || port.isEmpty()) {
            throw new RuntimeException("读写器连接COM口连接失败");
        }
        // 不一样的连接
        if(! port.equals(this.port)) {
            if(reader != null) {
                reader.disconnect();
            }
            this.port = port;
        }
        isStart = false;
        reader = ReaderImpl.create(AntennaCount.FOUR_CHANNELS);
        boolean connect = reader.connect(new JSerialPortHandle(port, baud));
        if(connect) {
            return;
        }
        throw new RuntimeException("读写器连接失败[port:"+port+"]"+"[baud:"+ baud +"]");
    }

    @Transactional(rollbackFor = Exception.class , isolation = Isolation.READ_COMMITTED)
    public synchronized boolean starScan(BooksCopyIncrementDto params) {
        log.info("[{}] 正在执行",Thread.currentThread().getName());

        if(isStart) {
            throw new RuntimeException("正在使用");
        }
        String port = sysConfigService.selectConfigByKey(configKey);
        if(reader == null || ! reader.isConnected()) {
            initReader(port);
        }
        if(this.port == null || ! this.port.equals(port)) {
            initReader(port);
        }
        isStart = true;

        // 两种都获取
        typeUse = params.getBooksType();
        cnTypeUse = params.getBooksCnType();

        threadPoolTaskExecutor.execute(() -> {
            log.info("Single Reader START");

            ReadConfig readConfig = buildReadTidParams();
            while (isStart) {
                log.info("Single Reader Use：{}",isStart);
                try {
                    TimeUnit.MILLISECONDS.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                reader.readTag(readConfig, suc -> {
                    String data = suc.getStrData().replace(" ","");
                    Boolean aBoolean = redisCache.redisTemplate.opsForHash().hasKey(cacheBuildKey, data);
                    log.info("MapKey：{}，IsMapKey：{};",data,aBoolean);
                    if (!aBoolean) {
                        // 数据
                        BooksCopyTempVo booksCopyTempVo = new BooksCopyTempVo();
                        booksCopyTempVo.setBooksType(typeUse);
                        booksCopyTempVo.setBooksCnType(cnTypeUse);
                        booksCopyTempVo.setBooksCopyLicense(cnTypeUse);
                        booksCopyTempVo.setBooksCopyStatus(params.getBooksCopyStatus());
                        booksCopyTempVo.setBooksId(params.getBooksId());
                        booksCopyTempVo.setBookShelfId(params.getBookShelfId());
                        booksCopyTempVo.setBooksCopyRuleId(params.getBooksCopyRuleId());
                        booksCopyTempVo.setBooksCopyRfid(data);

                        redisCache.redisTemplate.opsForHash().put(cacheBuildKey, data, booksCopyTempVo);
                        log.info("data：{}",booksCopyTempVo);
                    }
                }, err -> {
                    log.info("Single Reader ErrCode：{}",err.getErrorCode());
                });
            }
            log.info("Single Reader END");
        });
        return Boolean.TRUE;
    }

    List<String> scanRfidTest = List.of("E28278022000000008C91701","E28278022000000008C91799","E28278022000000008C91606","E28278022000000008C91831","E28278022000000008C91832","E28278022000000008C9179F","E28278022000000008C9099D","E28278022000000008C908A4","E28278022000000008C908A6","E28278022000000008C90A55","E28278022000000008C90A74","E28278022000000008C90D83","E28278022000000008C90A74","E28278022000000008C9086C","E28278022000000008C90A73","E28278022000000008C90B69","E28278022000000008C90D4B","E28278022000000008C90B68","E28278022000000008C90D4A","E28278022000000008C90C5F","E28278022000000008C90B85");
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.READ_COMMITTED)
    public synchronized boolean starScanTest(BooksCopyIncrementDto params) {
        if(isStart) {
            throw new RuntimeException("正在使用");
        }
        isStart = true;

        // 两种都获取
        typeUse = params.getBooksType();
        cnTypeUse = params.getBooksCnType();

        threadPoolTaskExecutor.execute(() -> {

            ReadConfig readConfig = buildReadTidParams();
            while (isStart) {
                try {
                    TimeUnit.MILLISECONDS.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                for (String data : scanRfidTest) {
                    Boolean aBoolean = redisCache.redisTemplate.opsForHash().hasKey(cacheBuildKey, data);
                    log.info("MapKey：{}，IsMapKey：{};",data,aBoolean);
                    if (!aBoolean) {
                        // 数据
                        BooksCopyTempVo booksCopyTempVo = new BooksCopyTempVo();
                        booksCopyTempVo.setBooksType(typeUse);
                        booksCopyTempVo.setBooksCnType(cnTypeUse);
                        booksCopyTempVo.setBooksCopyLicense(cnTypeUse);
                        booksCopyTempVo.setBooksCopyStatus(params.getBooksCopyStatus());
                        booksCopyTempVo.setBooksId(params.getBooksId());
                        booksCopyTempVo.setBookShelfId(params.getBookShelfId());
                        booksCopyTempVo.setBooksCopyRuleId(params.getBooksCopyRuleId());
                        booksCopyTempVo.setBooksCopyRfid(data);

                        redisCache.redisTemplate.opsForHash().put(cacheBuildKey, data, booksCopyTempVo);
                        log.info("data：{}",booksCopyTempVo);
                    }
                }
            }
        });
        return Boolean.TRUE;
    }

    @Transactional(rollbackFor = Exception.class , isolation = Isolation.READ_COMMITTED)
    public synchronized boolean stopScan() {
        log.info("[{}] 正在执行",Thread.currentThread().getName());

        // 未使用
        incrementService.update(Wrappers.lambdaUpdate(Increment.class)
                .set(Increment::getUse, IncrementStatus.UNUSE.getCode())
                .set(Increment::getIncrement, atomicCnType.get())
                .eq(Increment::getUse, IncrementStatus.USE.getCode())
                .in(Increment::getKey,"CnType:" + cnTypeUse)
        );

        isStart =false;
        reader.disconnect();

        typeUse ="";
        cnTypeUse ="";
        atomicCnType.set(0);
        redisCache.redisTemplate.expire(cacheBuildKey,1, TimeUnit.SECONDS);
        return Boolean.TRUE;
    }

    /**
     * 延迟获取读写器结果
     *  - 延迟指定时间，在指定时间内进行标签读写并返回数据
     * @return 列表
     */
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.READ_COMMITTED)
    public List<BooksCopyTempVo> autoScan(BooksCopyIncrementDto params) {
        boolean b = starScan(params);
        if(b) {
            try{
                Thread.sleep(2000);
                List data = data(DataInfoOption.BOOK_BUILD.getCode());
                stopScan();
                return data;
            } catch (Exception e) { }
        }
        return Collections.emptyList();
    }

    /** 开始扫描RFID识别数据 */
    public synchronized boolean starScanRfidBook() {

        log.info("[{}] 正在执行",Thread.currentThread().getName());

        if(isStart) {
            throw new RuntimeException("正在使用");
        }
        String port = sysConfigService.selectConfigByKey(configKey);
        if(reader == null || ! reader.isConnected()) {
            initReader(port);
        }
        if(this.port == null || ! this.port.equals(port)) {
            initReader(port);
        }
        isStart = true;

        threadPoolTaskExecutor.execute(() -> {
            log.info("Single Reader Book Rfid START");

            ReadConfig readConfig = buildReadTidParams();
            while (isStart) {
                log.info("Single Reader Book Rfid Use：{}",isStart);
                try {
                    TimeUnit.MILLISECONDS.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                reader.readTag(readConfig, suc -> {
                    String data = suc.getStrData().replace(" ","");
                    long isRedo = redisCache.redisTemplate.opsForSet().add(cacheInfoKey, data);
                    log.info("Single Reader Book Rfid 存储识别RFID缓存中是否存在：{}",isRedo);
                }, err -> {
                    log.info("Single Reader Book Rfid ErrCode：{}",err.getErrorCode());
                });
            }
            log.info("Single Reader Book Rfid END");
        });
        return Boolean.TRUE;
    }

    List<String> rfidFindTest = List.of(
        "E28278022000000008C90D4A",
        "E28278022000000008C90C5B",
        "E28278022000000008C90B68",
        "E28278022000000008C90D4B",
        "E28278022000000008C90C5C",
        "E28278022000000008C90B69",
        "E28278022000000008C90D4C",
        "E28278022000000008C90C5D",
        "E28278022000000008C90B6A",
        "E28278022000000008C90D4D",
        "E28278022000000008C90C5E",
        "E28278022000000008C90B6B",
        "E28278022000000008C90D4E",
        "E28278022000000008C90C5F",
        "E28278022000000008C90B6C",
        "E28278022000000008C90D66",
        "E28278022000000008C90C78",
        "E28278022000000008C90B85",
        "E28278022000000008C90E73",
        "E28278022000000008C90EDB",
        "E28278022000000008C90EDC"
    );
    public synchronized boolean starScanRfidBookTest() {

        log.info("[{}] TEST ",Thread.currentThread().getName());

        if(isStart) {
            throw new RuntimeException("正在使用");
        }
        isStart = true;
        threadPoolTaskExecutor.execute(() -> {

            while (isStart) {
                try {
                    TimeUnit.MILLISECONDS.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                rfidFindTest.forEach(rfid -> {
                    redisCache.redisTemplate.opsForSet().add(cacheInfoKey, rfid);
                });
            }
        });
        return Boolean.TRUE;
    }

    /** 停止扫描RFID查找书籍 */
    public synchronized boolean stopScanRfidBook() {
        isStart =false;
        reader.disconnect();

        redisCache.redisTemplate.expire(cacheInfoKey,1, TimeUnit.SECONDS);
        return Boolean.TRUE;
    }

    /** 开始扫描RFID识别书籍副本并保存 */
    public synchronized boolean starScanRfidFullBook() {

        log.info("[{}] 正在执行",Thread.currentThread().getName());

        if(isStart) {
            throw new RuntimeException("正在使用");
        }
        String port = sysConfigService.selectConfigByKey(configKey);
        if(reader == null || ! reader.isConnected()) {
            initReader(port);
        }
        if(this.port == null || ! this.port.equals(port)) {
            initReader(port);
        }
        isStart = true;

        threadPoolTaskExecutor.execute(() -> {
            log.info("Single Reader RFID TO PRINT START");

            ReadConfig readConfig = buildReadTidParams();
            while (isStart) {
                log.info("Single Reader RFID TO PRINT USE：{}",isStart);
                try {
                    TimeUnit.MILLISECONDS.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                reader.readTag(readConfig, suc -> {
                    String data = suc.getStrData().replace(" ","");
                    Boolean aBoolean = redisCache.redisTemplate.opsForHash().hasKey(cachePrintKey, data);
                    log.info("Print MapKey：{}，IsMapKey：{};",data,aBoolean);
                    if (!aBoolean) {
                        PrintRequireInfoData copy = printService.selectPrintRequireInfoDataList(PrintRequireInfoData.builder()
                                .booksCopyRfid(data)
                                .printStatus(PrintStatus.NO.getCode())
                                .build()
                        ).stream().findFirst().orElse(null);
                        if(copy != null) {
                            redisCache.redisTemplate.opsForHash().put(cachePrintKey, data, copy);
                        }
                        log.info("Single Reader RFID TO PRINT Data：{}",copy);
                    }
                }, err -> {
                    log.info("Single Reader RFID TO PRINT ErrCode：{}",err.getErrorCode());
                });
            }
            log.info("Single Reader RFID TO PRINT END");
        });
        return Boolean.TRUE;
    }

    /** 开始扫描RFID识别书籍副本并保存 */
    Set<String> cacheSet = Set.of("E282780220000000072204E5","E28278022000000008C900F4","E28278022000000008C901EC","E28278022000000008C90014","E28278022000000008C901EE","E28278020000000008C900F7","E28278020000000008C900F6","E28278020000000008C900F5","E28278020000000008C90017","E28278020000000008C901EC","E282788220000000036F1C12","E28278022000000008C90016","E28278022000000008C900F6","E28278022000000008C900F7","E28278022000000008C900F5","E28278022000000008C901ED","E282780200000000072204E5","E28278020000000008C901EE","E28278020000000008C90015","E28278020000000008C90016");
    public synchronized boolean starScanRfidFullBookTest() {
        if(isStart) {
            throw new RuntimeException("正在使用");
        }
        isStart = true;
        threadPoolTaskExecutor.execute(() -> {
            while (isStart) {
                try {
                    TimeUnit.MILLISECONDS.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                for (String data : cacheSet) {
                    Boolean aBoolean = redisCache.redisTemplate.opsForHash().hasKey(cachePrintKey, data);
                    log.info("Print MapKey：{}，IsMapKey：{};",data,aBoolean);
                    if (!aBoolean) {
                        PrintRequireInfoData copy = printService.selectPrintRequireInfoDataList(PrintRequireInfoData.builder()
                                .booksCopyRfid(data)
                                .printStatus(PrintStatus.NO.getCode())
                                .build()
                        ).stream().findFirst().orElse(null);
                        if(copy != null) {
                            redisCache.redisTemplate.opsForHash().put(cachePrintKey, data, copy);
                        }
                        log.info("Single Reader RFID TO PRINT Data：{}",copy);
                    }
                }
            }
        });
        return Boolean.TRUE;
    }

    public synchronized boolean stopScanRfidFullBook() {
        isStart =false;
        reader.disconnect();

        redisCache.redisTemplate.expire(cachePrintKey,1, TimeUnit.SECONDS);
        return true;
    }

    /**
     * @param option DataInfoOption 选项
     */
    public List data(String option) {
        if(DataInfoOption.BOOK_BUILD.equals(option)) {
            // BooksCopyTempVo 书籍构建数据
            return redisCache.redisTemplate.opsForHash().values(cacheBuildKey);
        }else if(DataInfoOption.BOOK_TID.equals(option)) {
            Set<String> cacheSet = redisCache.getCacheSet(cacheInfoKey);
            log.info("Reader RFID BookInfo Sets:{}",cacheSet);
            return List.copyOf(cacheSet);
        }else if(DataInfoOption.BOOK_PRINT.equals(option)) {
            return redisCache.redisTemplate.opsForHash().values(cachePrintKey);
        }
        return Collections.emptyList();
    }

    /** 读写器读TID区参数 */
    public ReadConfig buildReadTidParams() {
        ReadConfig.Builder builder = new ReadConfig.Builder();
        builder.setMemBank(MemBank.TID);
        builder.setWordLength((byte) 6);
        builder.setWordStartAddress((byte) 0);
        builder.setPasswords(new byte[] {0, 0, 0, 0});
        return builder.build();
    }

}
